package com.guit.apt;

import com.sun.mirror.type.AnnotationType;
import com.sun.mirror.type.ArrayType;
import com.sun.mirror.type.ClassType;
import com.sun.mirror.type.DeclaredType;
import com.sun.mirror.type.EnumType;
import com.sun.mirror.type.InterfaceType;
import com.sun.mirror.type.PrimitiveType;
import com.sun.mirror.type.ReferenceType;
import com.sun.mirror.type.TypeMirror;
import com.sun.mirror.type.TypeVariable;
import com.sun.mirror.type.VoidType;
import com.sun.mirror.type.WildcardType;
import com.sun.mirror.util.TypeVisitor;

import java.util.Collection;

public class ProxyVisitor implements TypeVisitor {

  private String qualifiedName;

  private final boolean allowPrimitives;

  public ProxyVisitor(boolean allowPrimitives) {
    this.allowPrimitives = allowPrimitives;
  }

  private String getProxy(DeclaredType arg0) {
    return ProxyProcessor.getProxyForType(arg0.getDeclaration());
  }

  @Override
  public void visitAnnotationType(AnnotationType arg0) {
  }

  @Override
  public void visitArrayType(ArrayType arg0) {
  }

  @Override
  public void visitClassType(ClassType arg0) {
    visitType(arg0);
  }

  public void visitType(DeclaredType arg0) {
    qualifiedName = getProxy(arg0);
    Collection<TypeMirror> arguments = arg0.getActualTypeArguments();
    if (arguments.size() > 0) {
      StringBuilder sb = new StringBuilder();
      for (TypeMirror typeMirror : arguments) {
        if (sb.length() > 0) {
          sb.append(", ");
        }

        ProxyVisitor visitor = new ProxyVisitor(allowPrimitives);
        typeMirror.accept(visitor);
        sb.append(visitor.getQualifiedName());
      }
      qualifiedName += "<" + sb.toString() + ">";
    }
  }

  @Override
  public void visitDeclaredType(DeclaredType arg0) {
    visitType(arg0);
  }

  @Override
  public void visitEnumType(EnumType arg0) {
    qualifiedName = arg0.getDeclaration().getQualifiedName();
  }

  @Override
  public void visitInterfaceType(InterfaceType arg0) {
    visitType(arg0);
  }

  @Override
  public void visitPrimitiveType(PrimitiveType arg0) {
    String primitive = arg0.getKind().name().toLowerCase();
    if (allowPrimitives) {
      qualifiedName = primitive;
    } else {
      qualifiedName =
          "java.lang." + primitive.substring(0, 1).toUpperCase() + primitive.substring(1);
    }
  }

  @Override
  public void visitReferenceType(ReferenceType arg0) {
  }

  @Override
  public void visitTypeMirror(TypeMirror arg0) {
  }

  @Override
  public void visitTypeVariable(TypeVariable arg0) {
  }

  @Override
  public void visitVoidType(VoidType arg0) {
    if (allowPrimitives) {
      qualifiedName = "void";
    } else {
      qualifiedName = Void.class.getCanonicalName();
    }
  }

  @Override
  public void visitWildcardType(WildcardType arg0) {
    qualifiedName = "wildcard";
  }

  public String getQualifiedName() {
    return qualifiedName;
  }
}
